package com.caocaog.market.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.caocaog.market.entity.GoodsBase;
import com.caocaog.market.entity.GoodsSpec;
import com.caocaog.market.entity.ShopCart;
import com.caocaog.market.mapper.ShopCartMapper;
import com.caocaog.market.service.GoodsBaseService;
import com.caocaog.market.service.GoodsSpecService;
import com.caocaog.market.service.ShopCartService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.CheckFailedException;
import org.jeecg.common.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * 购物车
 *
 * @author chechen
 * @date 2022-04-06
 */
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
@CacheConfig(cacheNames = CacheConstant.SHOPPING_CART_LIST)
public class ShopCartServiceImpl extends ServiceImpl<ShopCartMapper, ShopCart> implements ShopCartService {

    private RedisUtil redisUtil;
    private ShopCartService shopCartService;
    private GoodsSpecService goodsSpecService;
    private GoodsBaseService goodsBaseService;

    @Override
    @Cacheable(key = "'shopId:' + #shopId + ',memberId:' + #memberId", sync = true)
    public List<ShopCart> myShopCart(String memberId, String shopId) {
        return super.baseMapper.selectList(new LambdaQueryWrapper<ShopCart>()
                .eq(ShopCart::getMemberId, memberId)
                .eq(ShopCart::getShopId, shopId));
    }

    @Override
    @CachePut(key = "'shopId:' + #shopCart.shopId + ',memberId:' + #shopCart.memberId")
    public List<ShopCart> operateShopCart(ShopCart shopCart) {
        List<ShopCart> shopCartList = this.shopCartService.myShopCart(shopCart.getMemberId(), shopCart.getShopId());

        if (StringUtils.isBlank(shopCart.getId())) {
            log.info("从商品列表添加到购物车");
            return this.addShoppingCart(shopCart, shopCartList);
        } else {
            log.info("购物车操作数量");
            return this.editShoppingCart(shopCart, shopCartList);
        }
    }

    /**
     * 从商品列表添加到购物车
     */
    private List<ShopCart> addShoppingCart(ShopCart shopCart, List<ShopCart> shopCartList) {

        log.info("根据条件查询购物车中是否已经包含此商品");
        List<ShopCart> currentShopCartList = super.baseMapper.selectList(new LambdaQueryWrapper<ShopCart>()
                .eq(ShopCart::getShopId, shopCart.getShopId())
                .eq(ShopCart::getMemberId, shopCart.getMemberId())
                .eq(ShopCart::getGoodsId, shopCart.getGoodsId())
                .eq(StringUtils.isNotBlank(shopCart.getSpecId()), ShopCart::getSpecId, shopCart.getSpecId())
                .eq(StringUtils.isNotBlank(shopCart.getAttributeStr()), ShopCart::getAttributeStr, shopCart.getAttributeStr())
        );

        if (!currentShopCartList.isEmpty()) {
            log.info("包含");
            return this.operateShoppingCart(currentShopCartList.get(0), shopCart.getType(), shopCartList);
        }

        log.info("不包含");
        // 只在 type == 1 的时候加购，-1 就直接 return
        if (shopCart.getType() == -1) return shopCartList;

        log.info("判断库存数量是否还有剩余");
        shopCart.setNum(this.judgeInventoryQuantity(shopCart.getSpecId(), 0, shopCart.getType()));

        log.info("新增一条商品到购物车");
        int insertRecordCount = super.baseMapper.insert(shopCart);
        if (insertRecordCount > 0) {
            shopCartList.add(shopCart);
        }
        return shopCartList;
    }

    /**
     * 修改购物车内商品数量
     */
    private List<ShopCart> editShoppingCart(ShopCart shopCart, List<ShopCart> shopCartList) {
        if (shopCart.getType() != 1 && shopCart.getType() != -1) {
            throw new CheckFailedException("购物车商品的操作增减类型错误, type(1 or -1) but-> " + shopCart.getType());
        }
        log.info("先根据id查询购物车信息");
        ShopCart currentShopCart = super.baseMapper.selectById(shopCart.getId());
        if (currentShopCart == null) {
            throw new CheckFailedException("未查询到相应购物车信息, id-> " + shopCart.getId());
        }
        return this.operateShoppingCart(currentShopCart, shopCart.getType(), shopCartList);
    }

    /**
     * 操作购物车信息
     *
     * @param currentShopCart 购物车信息
     * @param type            加1 或 减-1
     * @return 受影响行数
     */
    private List<ShopCart> operateShoppingCart(ShopCart currentShopCart, int type, List<ShopCart> shopCartList) {

        log.info("判断库存数量是否还有剩余");
        Integer num = this.judgeInventoryQuantity(currentShopCart.getSpecId(), currentShopCart.getNum(), type);
        if (num <= 0) {
            log.info("删除购物车信息, id-> " + currentShopCart.getId());
            int deleteRecordCount = super.baseMapper.deleteById(currentShopCart.getId());
            if (deleteRecordCount > 0) {
                shopCartList.removeIf(next -> next.getId().equals(currentShopCart.getId()));
            }
            return shopCartList;
        }

        log.info("更新购物车内商品的数量");
        currentShopCart.setNum(num);
        int updateRecordCount = super.baseMapper.updateById(currentShopCart);
        if (updateRecordCount > 0) {
            for (ShopCart next : shopCartList) {
                if (next.getId().equals(currentShopCart.getId())) {
                    next.setNum(num);
                }
            }
        }
        return shopCartList;
    }

    /**
     * 判断库存数量是否还有剩余，并返回加购数量
     *
     * @param specId      商品规格id
     * @param shopCartNum 购物车中已有的数量
     * @param type        加1 或 减-1
     * @return 加购数量
     */
    private Integer judgeInventoryQuantity(String specId, Integer shopCartNum, int type) {
        GoodsSpec goodsSpec = this.goodsSpecService.getGoodsSpec(specId);
        if (goodsSpec == null)
            throw new CheckFailedException("未查询到相应商品规格信息");
        GoodsBase goodsBase = this.goodsBaseService.getByIdCache(goodsSpec.getGoodsId());
        if (goodsBase == null)
            throw new CheckFailedException("未查询到相应商品基础信息");
        // 库中有很多商品的起售数量还是0，所以这里做一些处理，如果起售数量小于1，则赋值1
        if (goodsBase.getSalesQuantity() < 1) goodsBase.setSalesQuantity(1);

        int num = shopCartNum;
        if (type == 1) {
            if (num >= goodsBase.getSalesQuantity()) {
                num++;
            } else {
                num += goodsBase.getSalesQuantity();
            }
            if (goodsSpec.getStock() < num)
                throw new CheckFailedException("已无库存");
        } else {
            if (num > goodsBase.getSalesQuantity()) {
                num--;
            } else {
                num -= goodsBase.getSalesQuantity();
            }
        }
        return num;
    }

    @Override
    @CachePut(key = "'shopId:' + #shopId + ',memberId:' + #memberId")
    public List<ShopCart> cleanShopCart(String memberId, String shopId) {
        int deleteRecordCount = super.baseMapper.delete(new LambdaQueryWrapper<ShopCart>()
                .eq(ShopCart::getMemberId, memberId)
                .eq(ShopCart::getShopId, shopId));
        if (deleteRecordCount == 0)
            log.error(String.format("清空购物车失败, memberId-> %s, shopId-> %s", memberId, shopId));

        return new ArrayList<>();
    }

    @Override
    public void cleanShopCart(String shopId) {
        int deleteRecordCount = super.baseMapper.delete(new LambdaQueryWrapper<ShopCart>()
                .eq(ShopCart::getShopId, shopId));
        if (deleteRecordCount == 0)
            log.error(String.format("清空店铺所有购物车失败, shopId-> %s", shopId));
        cleanCacheShopCart(shopId);
    }

    @Override
    public Long cleanCacheShopCart(String shopId) {
        String key = CacheConstant.SHOPPING_CART_LIST;
        if (StringUtils.isNotBlank(shopId)) {
            key += CommonConstant.DOUBLE_COLON + "shopId:" + shopId;
        }
        return this.redisUtil.removeAll(key);
    }


    @Autowired
    public void setRedisUtil(RedisUtil redisUtil) {
        this.redisUtil = redisUtil;
    }

    @Autowired(required = false)
    public void setShopCartService(@Lazy ShopCartService shopCartService) {
        this.shopCartService = shopCartService;
    }

    @Autowired
    public void setGoodsSpecService(GoodsSpecService goodsSpecService) {
        this.goodsSpecService = goodsSpecService;
    }

    @Autowired
    public void setGoodsBaseService(GoodsBaseService goodsBaseService) {
        this.goodsBaseService = goodsBaseService;
    }
}
